﻿using Cofe.Core.Property;
using Cofe.Core.Validater;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using Cofe.Core.Interfaces;

namespace Cofe.Core.Security
{

    public class VolumePermissionPolicy : IPermissionPolicy<IVolumeInfo>,
        IPermissionPolicy<IPropertyHost>, IXmlSerializable
    {
        #region Constructor

        public static VolumePermissionPolicy ForServices(string volumeId = null, PermissionType permission = PermissionType.All)
        {
            return new VolumePermissionPolicy()
            {
                _volumeId = null,
                _permission = permission,
                RequiredRole = new string[] { SecurityConstants.ServiceRole }
            };
        }


        public static VolumePermissionPolicy ForSpecificRole(string[] requireRole, string volumeId, PermissionType permission = PermissionType.All)
        {
            if (requireRole == null)
                throw new ArgumentException("requireRole");
            if (volumeId == null)
                throw new ArgumentException("Must specify volumeId");

            return new VolumePermissionPolicy()
            {
                _volumeId = volumeId,
                _permission = permission,
                RequiredRole = requireRole
            };
        }

        public static VolumePermissionPolicy ForAllVolume(string[] requireRole, PermissionType permission = PermissionType.All)
        {
            return new VolumePermissionPolicy()
            {
                _match = (path, permissionType) => permission.HasFlag(permissionType)
            };
        }

        public static VolumePermissionPolicy ForRootVolume()
        {
            return ForAnyRole("", PermissionType.Read | PermissionType.List);
        }

        public static VolumePermissionPolicy ForSpecificRole(string requireRole, string volumeId, PermissionType permission = PermissionType.All)
        {
            if (volumeId == null)
                throw new ArgumentException("Must specify volumeId");

            return ForSpecificRole(new string[] { requireRole }, volumeId, permission);
        }

        public static VolumePermissionPolicy ForAnyRole(string volumeId, PermissionType permission = PermissionType.All)
        {
            if (volumeId == null)
                throw new ArgumentException("Must specify volumeId");

            return new VolumePermissionPolicy()
            {
                _volumeId = volumeId,
                _permission = permission,
                RequiredRole = new string[] { }
            };
        }

        public static VolumePermissionPolicy ForUnmappedEntryList(PermissionType permission = PermissionType.All)
        {
            return new VolumePermissionPolicy()
            {
                _volumeId = "",
                _permission = permission,
                RequiredRole = new string[] { },
                _match = (volumeId, permissionType) =>
                    {
                        if (CofeServices.VolumeRegistrar.LookupVolume(volumeId) == null)
                            return permission.HasFlag(permissionType);
                        return false;
                    }

            };
        }

        public VolumePermissionPolicy()
        {
            _match = (volumeId, permissionType) =>
            {
                if (String.IsNullOrEmpty(_volumeId))
                    return _permission.HasFlag(permissionType);
                else return _permission.HasFlag(permissionType) && _volumeId.Equals(volumeId, StringComparison.CurrentCultureIgnoreCase);
            };

        }

        #endregion

        #region Methods


        public bool Match(IVolumeInfo requestedObj, PermissionType permissionType)
        {
            return _match(requestedObj.VolumeId, permissionType);
        }

        public bool Match(IPropertyHost requestedObj, PermissionType permissionType)
        {
            string volumeId = requestedObj.Behaviors.IsPropertySupported(CofeProperties.VolumeInfo) ? 
                requestedObj.Behaviors.GetProperty<IVolumeInfo>(CofeProperties.VolumeInfo).VolumeId : "";
            return _match(volumeId, permissionType);
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            reader.MoveToContent();

            reader.MoveToContent();
            RequiredRole = reader.GetAttribute("RequiredRole").Split(',');
            _permission = (PermissionType)Int32.Parse(reader.GetAttribute("Permission"));
            _volumeId = reader.GetAttribute("VolumeId");
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteAttributeString("RequiredRole", String.Join(",", RequiredRole));
            writer.WriteAttributeString("Permission", ((int)_permission).ToString());
            writer.WriteAttributeString("VolumeId", _volumeId);
        }

        public override string ToString()
        {
            return String.Format("Vol:{0} Role:{1} Perm:{2}", _volumeId, String.Join(",", RequiredRole), _permission);
        }

        #endregion

        #region Data

        private string _volumeId;
        private PermissionType _permission;
        private Func<string, PermissionType, bool> _match = null;




        #endregion

        #region Public Properties


        public string[] RequiredRole { get; private set; }
        public string VolumeId { get { return _volumeId; } }
        public PermissionType GrantedPermission { get { return _permission; } }

        #endregion







    }
}
